package edu.udel.mboch.towerdefense;

import java.util.ArrayList;
import java.util.Arrays;

public class Levels
{
	public static final String LEVEL1 =
			"--------------------\n" +
			"s -------------    e\n" +
			"- ---------     ----\n" +
			"- --------- --------\n" +
			"-     ----- --------\n" +
			"-----   --- --------\n" +
			"------- --- --------\n" +
			"------- --- --------\n" +
			"-------     --------\n" +
			"--------------------\n";

	public static final String LEVEL2 =
			"--------------------\n" +
			"s                  e\n" +
			"- ---------     ----\n" +
			"- --------- --------\n" +
			"-     ----- --------\n" +
			"-----   --- --------\n" +
			"------- --- --------\n" +
			"------- --- --------\n" +
			"-------     --------\n" +
			"--------------------";

	public static final String LEVEL3 =
			"---------1----------\n" +
			"--------- ----------\n" +
			"-------   ----------\n" +
			"------- ------------\n" +
			"------- sS ---------\n" +
			"---------- ---------\n" +
			"---------- ---------\n" +
			"---------  ---------\n" +
			"--------- ----------\n" +
			"---------2----------";
	
	private static String RANDOM_LEVEL;
	public static ArrayList<PathPosition> RANDOM_PATH;
	
	public static final int[] EASY = new int[]{50,75};
	public static final int[] MEDIUM = new int[]{35,50};
	public static final int[] HARD = new int[]{25,35};
	
	public static Grid loadFromStringSP(String stream)
	{
		String[] terrain = stream.split("\n");
		Terrain[][] tGrid = new Terrain[Grid.MAX_Y][Grid.MAX_X];
		Position spawn = new Position(0,0);
		Position end = new Position(0,0);
		for(int i = 0; i<Grid.MAX_Y; i++)
		{
			char[] encoded = terrain[i].toCharArray();
			for(int j = 0; j<encoded.length; j++)
			{
				if(encoded[j] == '-')
					tGrid[i][j] = new Metal(new Position(j,i));
				else if(encoded[j] == ' ')
					tGrid[i][j] = new Road(new Position(j,i));
				else if(encoded[j] == 's')
				{
					spawn = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j, i));
				}
				else if(encoded[j] == 'e')
				{
					end = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j, i));
				}
			}
		}
		Grid grid = new SinglePlayerGrid(spawn, end, tGrid);
		return grid;
	}
	
	public static Grid loadFromStringRandomSP(int[] difficulty)
	{
		while(!Levels.generateRandomSP(difficulty));
		String[] terrain = RANDOM_LEVEL.split("\n");
		Terrain[][] tGrid = new Terrain[Grid.MAX_Y][Grid.MAX_X];
		Position spawn = new Position(0,0);
		Position end = new Position(0,0);
		for(int i = 0; i<Grid.MAX_Y; i++)
		{
			char[] encoded = terrain[i].toCharArray();
			for(int j = 0; j<encoded.length; j++)
			{
				if(encoded[j] == '-')
					tGrid[i][j] = new Metal(new Position(j,i));
				else if(encoded[j] == ' ')
					tGrid[i][j] = new Road(new Position(j,i));
				else if(encoded[j] == 's')
				{
					spawn = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j, i));
				}
				else if(encoded[j] == 'e')
				{
					end = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j, i));
				}
			}
		}
		Grid grid = new SinglePlayerGrid(new Tower[Grid.MAX_Y][Grid.MAX_X], new Mob[Grid.MAX_Y][Grid.MAX_X], tGrid, spawn, end, RANDOM_PATH, new ArrayList<Mob>(), new ArrayList<Projectile>());
		return grid;
	}

	public static BattleGrid loadFromStringB(String stream)
	{
		String[] terrain = stream.split("\n");
		Terrain[][] tGrid = new Terrain[Grid.MAX_Y][Grid.MAX_X];
		Position spawn = new Position(0,0);
		Position spawn2 = new Position(0,0);
		Position end = new Position(0,0);
		Position end2 = new Position(0,0);
		for(int i = 0; i<Grid.MAX_Y; i++)
		{
			char[] encoded = terrain[i].toCharArray();
			for(int j = 0; j<encoded.length; j++)
			{
				if(encoded[j] == '-')
					tGrid[i][j] = new Metal(new Position(j,i));
				else if(encoded[j] == ' ')
					tGrid[i][j] = new Road(new Position(j,i));
				else if(encoded[j] == 's')
				{
					spawn = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j, i));
				}
				else if(encoded[j] == 'S')
				{
					spawn2 = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j,i));
				}
				else if(encoded[j] == '1')
				{
					end = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j, i));
				}
				else if(encoded[j] == '2')
				{
					end2 = new Position(j, i);
					tGrid[i][j] = new Road(new Position(j, i));
				}
			}
		}
		BattleGrid grid = new BattleGrid(spawn, spawn2, end, end2, tGrid);
		return grid;
	}
	
	public static boolean generateRandomSP(int[] difficulty)
	{
		RANDOM_LEVEL = "";
		RANDOM_PATH = new ArrayList<PathPosition>();
		ArrayList<Integer> sides = new ArrayList<Integer>(Arrays.asList(new Integer[]{0,1,2,3})); //sides are 0,1,2,3 in order of l,t,r,b
		int startSide = sides.remove((int)(Math.random()*4));
		int endSide;
		PathPosition spawn;
		int dir;
		if(startSide == 0)
		{
			spawn = new PathPosition(0, (int)(Math.random()*Grid.MAX_Y), 0);
			dir = 2;
			endSide = 2;
		}
		else if(startSide == 1)
		{
			spawn = new PathPosition((int)(Math.random()*Grid.MAX_X), 0, 0);
			dir = 3;
			endSide = 3;
		}
		else if(startSide == 2)
		{
			spawn = new PathPosition(Grid.MAX_X-1, (int)(Math.random()*Grid.MAX_Y), 0);
			dir = 0;
			endSide = 0;
		}
		else
		{
			spawn = new PathPosition((int)(Math.random()*Grid.MAX_X), Grid.MAX_Y-1, 0);
			dir = 1;
			endSide = 1;
		}
		Position end;
		if(endSide == 0)
			end = new Position(0, (int)(Math.random()*Grid.MAX_Y));
		else if(endSide == 1)
			end = new Position((int)(Math.random()*Grid.MAX_X), 0);
		else if(endSide == 2)
			end = new Position(Grid.MAX_X-1, (int)(Math.random()*Grid.MAX_Y));
		else
			end = new Position((int)(Math.random()*Grid.MAX_X), Grid.MAX_Y-1);
		
		ArrayList<Position> positions = new ArrayList<Position>();
		positions.add(spawn);
		int count = 0;
		Position current = spawn.copy();
		RANDOM_PATH.add(new PathPosition(spawn.x(), spawn.y(), count++));
		int lastTurn = 0;
		while(!current.equals(end))
		{
			boolean moveMade = false;
			int move = (int)(Math.random()*2);
			Position next = null;
			if(move == 0 && !moveMade) //move forward
			{
				if(dir == 0 && current.x() != 0)
				{
					next = new Position(current.x()-1, current.y());
					if(!positions.contains(next))
						moveMade = true;
				}
				else if(dir == 1 && current.y() != 0)
				{
					next = new Position(current.x(), current.y()-1);
					if(!positions.contains(next))
						moveMade = true;
				}
				else if(dir == 2 && current.x() != Grid.MAX_X-1)
				{
					next = new Position(current.x()+1, current.y());
					if(!positions.contains(next))
						moveMade = true;
				}
				else if(dir == 3 && current.y() != Grid.MAX_Y-1)
				{
					next = new Position(current.x(), current.y()+1);
					if(!positions.contains(next))
						moveMade = true;
				}
				if(moveMade && next!=null)
				{
					positions.add(next);
					RANDOM_PATH.add(new PathPosition(next.x(), next.y(), count++));
					current = next.copy();
					lastTurn++;
				}
			}
			if(!moveMade && lastTurn >= 2) //Turn
			{
				if((int)(Math.random()*2) == 0) //Turn right
				{
					dir++;
					if(dir>3)
						dir = 0;
				}
				else
				{
					dir--;
					if(dir<0)
						dir = 3;
				}
				lastTurn = 0;
				moveMade = true;
			}
			if(move != 0 && !moveMade)
			{
				if(dir == 0 && current.x() != 0)
				{
					next = new Position(current.x()-1, current.y());
					if(!positions.contains(next))
						moveMade = true;
				}
				else if(dir == 1 && current.y() != 0)
				{
					next = new Position(current.x(), current.y()-1);
					if(!positions.contains(next))
						moveMade = true;
				}
				else if(dir == 2 && current.x() != Grid.MAX_X-1)
				{
					next = new Position(current.x()+1, current.y());
					if(!positions.contains(next))
						moveMade = true;
				}
				else if(dir == 3 && current.y() != Grid.MAX_Y-1)
				{
					next = new Position(current.x(), current.y()+1);
					if(!positions.contains(next))
						moveMade = true;
				}
				if(moveMade && next!=null)
				{
					positions.add(next);
					RANDOM_PATH.add(new PathPosition(next.x(), next.y(), count++));
					current = next.copy();
					lastTurn++;
				}
			}
			if(!moveMade)
				return false;
		}
		
		if(positions.size() <= difficulty[0] || positions.size() > difficulty[1])
			return false;
		
		Terrain[][] tGrid = new Terrain[Grid.MAX_Y][Grid.MAX_X];
		for(Position p : positions)
			tGrid[p.y()][p.x()] = new Road(new Position(p.x(), p.y()));
		for(int i = 0; i<Grid.MAX_Y; i++)
		{
			for(int j = 0; j<Grid.MAX_X; j++)
			{
				if(spawn.y() == i && spawn.x() == j)
					RANDOM_LEVEL += "s";
				else if(end.y() == i && end.x() == j)
					RANDOM_LEVEL += "e";
				else if(tGrid[i][j] == null)
					RANDOM_LEVEL += "-";
				else
					RANDOM_LEVEL += " ";
			}
			RANDOM_LEVEL += "\n";
		}
		return true;
	}
}
